#pragma once

#include "QvObject.h"

// abstract iteration position
struct __POSITION {};
typedef __POSITION* POSITION;

#define BEFORE_START_POSITION ((POSITION)-1L)

class QvPlex : public QvObject  // warning variable length structure
{
public:
    QvPlex* pNext;
#ifndef _WIN64
    #if (_AFX_PACKING >= 8)
        DWORD dwReserved[1];    // align on 8 byte boundary
    #endif
#endif
    // BYTE data[maxNum*elementSize];
    QvData data() { return (this + 1); }
    static QvPlex* PASCAL Create(QvPlex*& head, UINT_PTR nMax, UINT_PTR cbElement);
    // like 'calloc' but no zero fill
    // may throw memory exceptions
    void FreeDataChain(); // free this one and links
};

class QvToolkit_Export QvMapPtrToPtr : public QvObject
{
protected:
    // Association
    class QvAssoc : public QvObject
    {
    public:
        QvAssoc* pNext;
        QvData key;
        QvData value;
    };

public:
    QvMapPtrToPtr(QvInt32 nBlockSize = 10);

    virtual ~QvMapPtrToPtr();

// Attributes
    // number of elements
    QvInt32 GetCount() const;
    QvInt32 GetSize() const;
    QvBoolean IsEmpty() const;

    // Lookup
    QvBoolean Lookup(QvData key, QvData& rValue) const;

// Operations
    // Lookup and add if not there
    QvData& operator[](QvData key);

    // add a new (key, value) pair
    void SetAt(QvData key, QvData newValue);

    // removing existing (key, ?) pair
    QvBoolean RemoveKey(QvData key);
    void RemoveAll();

    // iterating all (key, value) pairs
    POSITION GetStartPosition() const;
    void GetNextAssoc(POSITION& rNextPosition, QvData& rKey, QvData& rValue) const;

    // advanced features for derived classes
    QvUInt32 GetHashTableSize() const;
    void InitHashTable(QvUInt32 hashSize);

    QvData GetValueAt(QvData key) const; 

// Implementation
protected:
    QvAssoc**   m_pHashTable;
    QvUInt32    m_nHashTableSize;
    QvInt32     m_nCount;
    QvAssoc*    m_pFreeList;
    QvPlex*     m_pBlocks;
    QvInt32     m_nBlockSize;

    QvAssoc* NewAssoc();
    void FreeAssoc(QvAssoc*);
    QvAssoc* GetAssocAt(QvData, QvUInt32&, QvUInt32&) const;

};

